-- BineM
-- Created by panyl
-- 魔藤模块

module("BineM", package.seeall);

local bines = {};
local bineSkills = {};

local whenLeaveDungeon;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    bines = {};
    bineSkills = {};

    -- 转换下bine信息表
    local bine_CSV = get_bine_CSV();
    for i = 1, #bine_CSV do
        bines[bine_CSV[i].class_id] = bine_CSV[i];

        -- 解析动作帧范围
        parseActionFrameRange(bine_CSV[i]);
    end

    bine_CSV = {};

    -- bine_skill表
    local bine_skill_CSV = get_bine_skill_CSV();
    for i = 1, #bine_skill_CSV do
        local row = bine_skill_CSV[i];
        bineSkills[row.skill_id] = row;

        -- 技能整理
        bines[row.class_id]["skills"] = bines[row.class_id]["skills"] or {};

        table.insert(bines[row.class_id]["skills"], row.skill_id);
    end

    bine_skill_CSV = {};
end

function init()
    loadCsv();

    -- 关注进入下一层地牢事件
    EventMgr.removeAll("BineM");

    -- 关注离开地牢事件
    EventMgr.register("BineM", event.LEAVE_DUNGEON, whenLeaveDungeon);

    -- 关注层数回退（大地之门等技能）的事件
    EventMgr.register("BineM", event.BACK_FLOOR, function()
        whenBackFloor();
    end);

    -- 开始新回合
    CombatM.registerEndRoundCB("bine_attack", attack);

    -- 开始打包验证客户端结果
    EventMgr.register("BineM", event.START_PACK_VERIFY_RESULT, function(para)
        syncBineData();
    end);
end

-- 解析动作的帧范围
function parseActionFrameRange(info)
    -- 待机、攻击前摇、施法前摇、死亡
    local fields = { "idle_frame", "pre_attack_frame",
                     "pre_cast_frame", "die_frame",};

    for _, field in pairs(fields) do
        local range = info[field];
        if not string.startWith(range, "[") or not string.endWith(range, "]") then
            error(string.format("字段(%s)配置格式错误!", tostring(field)));
            return info;
        end

        local arr = string.explode(string.sub(range, 2, -2),",");
        if #arr ~= 2 then
            error(string.format("字段(%s)配置格式错误!", tostring(field)));
            return info;
        end

        info[field] = { tonumber(arr[1]), tonumber(arr[2]) };
    end

    return info;
end

-- 进入下一层
function nextFloor()
    -- 先同步一下
    syncBineData();

    local info = ME.user.dbase:query("bine");
    if type(info) ~= "table" or type(info.class_id) ~= "number" then
        return;
    end

    -- 旧对象干掉
    ME.user.bine = nil;

    -- 创建魔藤对象
    local bine = createBine(info.class_id, info);
    if not bine then
        return;
    end

    -- 删除上次行动的回合
    bine.action = 1;

    syncBineData();

    if bine:isDead() then
        syncBineData();
        return;
    end

    -- 自动增加10%的生命,10+2.5%的魔法，暂时固定
    local hp = math.modf(bine:getHp() + bine:getMaxHp() / 10);
    local mp = math.modf(bine:getMp() + bine:getMaxMp() / 40 + 10);

    hp = math.min(hp, bine:getMaxHp());
    mp = math.min(mp, bine:getMaxMp());

    bine:setHp(hp);
    bine:setMp(mp);

    syncBineData();
end

-- 离开地牢，直接丢弃魔藤数据
whenLeaveDungeon = function()
    ME.user.bine = nil;
    ME.user.dbase:delete("bine");
    ME.user.dbase:delete("bine_attrib");

    -- 删除魔藤技能给玩家的属性加成
    ME.user.dbase:delete("bine_addon");
end

-- 开始新一层地牢
function startFloor()
    -- 同步一次属性
    syncBineData();

    local info = ME.user.dbase:query("bine");

    if type(info) ~= "table" or type(info.class_id) ~= "number" then
        return;
    end

    -- 旧对象不用了
    ME.user.bine = nil;

    createBine(info.class_id, info);
end

-- 回退楼层
function whenBackFloor()
    -- 先同步一下
    syncBineData();

    local info = ME.user.dbase:query("bine");

    if type(info) ~= "table" or type(info.class_id) ~= "number" then
        return;
    end

    -- 旧对象不用了
    ME.user.bine = nil;

    local bine = createBine(info.class_id, info);
    if bine then
        bine.action = 1;
    end

    syncBineData();
end

-- 检索
function query(classId, path)
    local m = bines[classId];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 检索魔藤技能
function querySkill(skillId, path)
    local m = bineSkills[skillId];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 获取所有植物
function getAllPlants()
    return table.keys(bines);
end

-- 获取花园位置
function getGardenPos()
    local pos = 0;
    for index = 1, GRID_SIZE do
        local grid = DungeonM.getGridByPos(index);
        if grid.type == GRID_TYPE_GARDEN then
            pos = grid:getPos();
            break;
        end
    end

    return pos;
end

-- 初始化花园/魔藤
function initGardenData()
    local ret = { ["garden_state"] = GARDEN_EMPTY, };

    -- 如果玩家当前没有魔藤数据，花园就是空的
    local bineInfo = ME.user.dbase:query("bine");
    local bine = ME.user.bine;
    if bine or bineInfo and bineInfo.class_id then
        local classId;
        if bine then
            classId = bine.classId;
        else
            classId = bineInfo.class_id;
        end
        ret = {
            ["garden_state"] = GARDEN_BINE,
            ["class_id"]     = classId,
        };
    end

    return ret;
end

-- 消耗
function doCost(cost)
    for key, amount in pairs(cost) do
        if type(key) == "number" then
            ItemM.costAmount(ME.user, key, amount);
        elseif type(key) == "string" then
            ME.user:costAttrib(key, amount);
        end
    end
end

-- 创建一个魔藤
function createBine(classId, info)
    info = info or {};

    local dbase = table.add({
        ["class_id"] = classId,
        ["level"]  = info["level"] or 1,
        ["skills"] = {},
        ["pos"]    = getGardenPos(),
    }, info);

    local bine = Bine.new(classId, dbase);
    ME.user.bine = bine;

    bine.action = info["action"] or CombatM.getRound();

    PropM.refresh(bine);

    return bine;
end

-- 判断能否升级魔藤技能
function canUpgradeSkill(skillId)
    local bine = ME.user.bine;

    if not bine then
        trace("BineM", "玩家当前没有魔藤。");
        return false;
    end

    if not bine:ownSkill(skillId) then
        trace("BineM", "魔藤%s当前没有技能%d，不能升级。", bine:getName(), skillId);
        return false;
    end

    local baseSkill = SkillM.findBaseSkill(skillId);
    if (bine:getSkillLevel(skillId) >= querySkill(baseSkill, "max_level")) then
        trace("BineM", "魔藤%s的技能%s已经达到最高等级",
            bine:getName(), SkillM.query(baseSkill, "name"));
        return false;
    end

    -- 消耗
    local cost = FormulaM.invoke("CALC_UPGRADE_BINE_SKILL_COST", skillId);
    if type(cost) ~= 'table' then
        error("魔藤技能(%d)升级消耗配置有误", skillId);
    end

    local ok = true;
    for classId, amount in pairs(cost) do
        if type(classId) == "number" then
            ok = ItemM.getAmount(ME.user, classId) >= amount;
        elseif type(classId) == "string" then
            ok = ME.user.dbase:query(classId, 0) >= amount;
        end

        if true ~= ok then
            return "cost_lack";
        end
    end

    return ok;
end

-- 升级技能
function upgradeBineSkill(skillId)
    -- 先判断下
    if true ~= canUpgradeSkill(skillId) then
        return false;
    end

    -- 先做消耗
    local cost = FormulaM.invoke("CALC_UPGRADE_BINE_SKILL_COST", skillId);
    doCost(cost);

    local bine = ME.user.bine;
    bine:upgradeSkill(skillId);

    DungeonLogM.addLog(string.format("魔藤升级技能%d。", skillId));

    -- 刷新下属性
    PropM.refresh(bine);

    -- 抛出事件
    EventMgr.fire(event.BINE_UPGRADE_SKILL, { ["skillId"] = skillId, });
    return true;
end

-- 能否升级
function canLevelUp()
    local bine = ME.user.bine;
    if not bine then
        trace("BineM", "玩家没有魔藤。");
        return false;
    end

    local level = bine:getLevel();
    if level >= query(bine.classId, "max_level") then
        trace("BineM", "魔藤%s已经达到最高等级，不能再升级。", bine:getName());
        return "level_upper";
    end

    -- 判断消耗
    local ok = true;
    local cost = FormulaM.invoke("CALC_BINE_COST", "level_up", bine.classId);
    for classId, amount in pairs(cost) do
        if type(classId) == "number" then
            ok = ItemM.getAmount(ME.user, classId) >= amount;
        elseif type(classId) == "string" then
            ok = ME.user.dbase:query(classId, 0) >= amount;
        end

        if true ~= ok then
            return "cost_lack";
        end
    end

    return ok;
end

-- 魔藤升级
function levelUp()
    if true ~= canLevelUp() then
        return false;
    end

    -- 先消耗
    local bine = ME.user.bine;
    local cost = FormulaM.invoke("CALC_BINE_COST", "level_up", bine.classId);
    doCost(cost);

    -- 升一级
    local level = bine:getLevel();
    local newLevel = level + 1;

    local hp = bine.dbase:query("hp", 0);
    local mp = bine.dbase:query("mp", 0);

    hp = hp + FormulaM.invoke("BINE_BASE_HP", newLevel) - FormulaM.invoke("BINE_BASE_HP", level);
    mp = mp + FormulaM.invoke("BINE_BASE_MP", newLevel) - FormulaM.invoke("BINE_BASE_MP", level);

    bine.dbase:set("hp", hp);
    bine.dbase:set("mp", mp);
    bine:setLevel(newLevel);

    syncBineData();

    DungeonLogM.addLog(string.format("魔藤升到%d级，hp=%d，mp=%d", bine:getLevel(), bine:queryAttrib("hp"), bine:queryAttrib("mp")));

    -- 抛出事件
    EventMgr.fire(event.BINE_LEVEL_UP, { ["level"] = newLevel, });

    -- 刷新下属性
    PropM.refresh(bine);
    return true;
end

-- 判断能否恢复
function canCure()
    local bine = ME.user.bine;
    if not bine then
        trace("BineM", "玩家没有魔藤");
        return false;
    end

    -- 如果魔藤已经死亡了
    if bine:isDead() then
        trace("BineM", "魔藤已经死亡了，不能恢复");
        return "bine_dead";
    end

    -- 判断消耗
    local ok = true;
    local cost = FormulaM.invoke("CALC_BINE_COST", "cure", bine.classId);
    for classId, amount in pairs(cost) do
        if type(classId) == "number" then
            ok = ItemM.getAmount(ME.user, classId) >= amount;
        elseif type(classId) == "string" then
            ok = ME.user.dbase:query(classId, 0) >= amount;
        end

        if true ~= ok then
            return "cost_lack";
        end
    end

    return ok;
end

-- 治疗魔藤
function cureBine()
    -- 判断下
    if true ~= canCure() then
        return false;
    end

    local bine = ME.user.bine;
    local cost = FormulaM.invoke("CALC_BINE_COST", "cure", bine.classId);
    doCost(cost);

    -- 暂时简陋一点
    local recover = FormulaM.invoke("CALC_BINE_CURE_RECOVER");
    local hp = bine:getHp() + recover["hp"];
    local mp = bine:getMp() + recover["mp"];

    hp = math.min(hp, bine:getMaxHp());
    mp = math.min(mp, bine:getMaxMp());

    bine:setHp(hp);
    bine:setMp(mp);

    DungeonLogM.addLog(string.format("魔藤hp恢复%d，mp恢复%d。", recover["hp"], recover["mp"]));

    -- 抛出事件
    EventMgr.fire(event.CURE_BINE);
    return true;
end

-- 判断能否复活
function canRevive()
    local bine = ME.user.bine;
    if not bine then
        trace("BineM", "玩家没有魔藤，不能复活。");
        return false;
    end

    -- 魔藤没死亡
    if not bine:isDead() then
        trace("BineM", "魔藤没死亡。");
        return false;
    end

    -- 消耗
    local ok = true;
    local cost = FormulaM.invoke("CALC_BINE_COST", "revive", bine.classId);
    for classId, amount in pairs(cost) do
        if type(classId) == "number" then
            ok = ItemM.getAmount(ME.user, classId) >= amount;
        elseif type(classId) == "string" then
            ok = ME.user.dbase:query(classId, 0) >= amount;
        end

        if true ~= ok then
            return "cost_lack";
        end
    end

    return ok;
end

-- 复活魔藤
function reviveBine()
    -- 判断下
    if true ~= canRevive() then
        return false;
    end

    local bine = ME.user.bine;
    local cost = FormulaM.invoke("CALC_BINE_COST", "revive", bine.classId);
    doCost(cost);

    -- 复活
    local hp = calcReviveHp(bine);
    local mp = math.modf(bine:getMp() + bine:getMaxMp() / 10);

    mp = math.min(mp, bine:getMaxMp());
    bine:revive(hp, mp);

    DungeonLogM.addLog(string.format("魔藤复活hp=%d，mp=%d", bine:queryAttrib("hp"), bine:queryAttrib("mp")));

    -- 抛出事件
    EventMgr.fire(event.BINE_REVIVE);
    return true;
end

-- 计算魔藤复活可恢复的生命值
function calcReviveHp(bine)
    return math.modf(bine:getMaxHp() / 10);
end

-- 计算施放技能消耗
function calcSkillCost(skillId)
    -- 魔法值
    local baseSkill = SkillM.findBaseSkill(skillId);
    return querySkill(baseSkill, "require");
end

-- 判断能否使用技能
function canUseSkill(skillId, pos)
    local bine = ME.user.bine;
    if not bine or bine:isDead() then
        trace("BineM", "没有魔藤或者魔藤已经死亡。");
        return false;
    end

    -- 魔藤是否拥有此技能
    if not bine:ownSkill(skillId) then
        trace("BineM", "魔藤没有技能%s。", SkillM.query(skillId, "name"));
        return false;
    end

    -- 魔法值
    local mp = calcSkillCost(skillId);
    if bine:getMp() < mp then
        trace("BineM", "魔藤魔法值不足，当前：%d，需求：%d。", bine:getMp(), mp);
        return false;
    end

    -- 是否有效目标
    local grid = DungeonM.getGridByPos(pos);
    local monster = grid.monster;

    if not grid:isMonster() or not monster or monster:isDead() then
        trace("BineM", "目标%d不是存活的怪物。", pos);
        return false;
    end

    return true;
end

-- 使用技能
function useSkill(skillId, pos)
    -- 判断
    if true ~= canUseSkill(skillId, pos) then
        return false;
    end

    local mp = calcSkillCost(skillId);

    local bine = ME.user.bine;
    local grid = DungeonM.getGridByPos(pos);
    local monster = grid.monster;

    -- 消耗魔法值
    bine:setMp(bine:getMp() - mp);

    local msg = string.format("魔藤使用技能，消耗魔法值：%d，当前魔法值：%d，最大魔法值：%d。", mp, bine:getMp(), bine:getMaxMp());
    DungeonLogM.addLog(msg);

    -- 施放技能
    local assailantInfo = {
        ["source"] = bine,
        ["skill_id"] = skillId,
    };
    SkillM.apply(bine, monster, skillId, CombatM.getRound(), { assailantInfo = assailantInfo });

    -- 抛出事件
    EventMgr.fire(event.BINE_USE_SKILL, { ["skillId"] = skillId, ["pos"] = pos, });

    -- 一个回合事件
    EventMgr.fire(event.COMBAT_ROUND, pos);

    return true;
end

-- 判断能否学习技能
function canLearnSkill(skillId)
    local bine = ME.user.bine;
    if not bine then
        trace("BineM", "没有魔藤，不能学习魔藤技能。");
        return false;
    end

    local skills = query(bine.classId, "skills");
    if table.indexOf(skills, skillId) <= 0 then
        trace("BineM", "魔藤不能学习此技能。");
        return false;
    end

    if bine:ownSkill(skillId) then
        trace("BineM", "魔藤已经拥有此技能。");
        return false;
    end

    -- 消耗
    local ok = true;
    local cost = FormulaM.invoke("CALC_BINE_LEARN_SKILL_COST", skillId);
    for classId, amount in pairs(cost) do
        if type(classId) == "number" then
            ok = ItemM.getAmount(ME.user, classId) >= amount;
        elseif type(classId) == "string" then
            ok = ME.user.dbase:query(classId, 0) >= amount;
        end

        if true ~= ok then
            return "cost_lack";
        end
    end

    return ok;
end

-- 学习技能
function learnSkill(skillId)
    if true ~= canLearnSkill(skillId) then
        return false;
    end

    local cost = FormulaM.invoke("CALC_BINE_LEARN_SKILL_COST", skillId);
    doCost(cost);

    local bine = ME.user.bine;
    bine:learnSkill(skillId);

    -- 同步一次数据
    syncBineData();

    -- 刷新下属性
    PropM.refresh(bine);

    -- 抛出事件
    EventMgr.fire(event.BINE_LEARN_SKILL, { ["skillId"] = skillId, });
    return true;
end

-- 能否种植
function canPlant(pos, id)
    local grid = DungeonM.getGridByPos(pos);

    -- 如果不是花园
    if  grid.type ~= GRID_TYPE_GARDEN or
        grid.garden_state ~= GARDEN_EMPTY then
        trace("BineM", "花园已经种植过了。");
        return "had_planted";
    end

    -- 消耗
    local ok = true;
    local cost = FormulaM.invoke("CALC_BINE_COST", "plant", id);
    for classId, amount in pairs(cost) do
        if type(classId) == "number" then
            ok = ItemM.getAmount(ME.user, classId) >= amount;
        elseif type(classId) == "string" then
            ok = ME.user.dbase:query(classId, 0) >= amount;
        end

        if true ~= ok then
            -- 消耗不足
            return "lack_cost";
        end
    end

    return ok;
end

-- 种植魔藤
function plantBine(pos, id)
    local classId = id or 1;    -- 默认是魔藤1
    if true ~= canPlant(pos, classId) then
        return false;
    end

    -- 先消耗
    local cost = FormulaM.invoke("CALC_BINE_COST", "plant", classId);
    doCost(cost);

    local grid = DungeonM.getGridByPos(pos);
    grid.garden_state = GARDEN_BINE;
    grid.class_id     = classId;

    -- 直接来一个魔藤
    createBine(classId, {["pos"] = pos, });
    if DungeonM.isCostRound(grid) then
        -- 抛出一个回合事件
        EventMgr.fire(event.COMBAT_ROUND, pos);
    end

    -- 抛出事件
    EventMgr.fire(event.PLANT_BINE, { ["pos"] = pos, });

    return true;
end

-- 能否制造太阳花
function canMakeSunshine(pos)
    local grid = DungeonM.getGridByPos(pos);

    -- 如果不是太阳花
    local bine = ME.user.bine;
    if grid.type ~= GRID_TYPE_GARDEN or not bine then
        return false;
    end

    local classId = bine.classId;
    if query(classId, "alias") ~= "sunflower" then
        -- 不是太阳花
        return false;
    end

    -- 是否有足够的原料
    local material = query(classId, "material") or {};
    for id, amount in pairs(material) do
        if ItemM.getAmount(ME.user, id) < amount then
            return false;
        end
    end

    return true;
end

-- 制造太阳光
function makeSunshine(pos)
    -- 判断
    if not canMakeSunshine(pos) then
        return false;
    end

    local grid = DungeonM.getGridByPos(pos);
    local bine = ME.user.bine;

    -- 扣除原料
    local material = query(bine.classId, "material") or {};
    for id, amount in pairs(material) do
        ItemM.costAmount(ME.user, id, amount);
    end

    -- 给与奖励
    local produce = query(bine.classId, "produce");
    for id, amount in pairs(produce) do
        BonusM.doBonus({ 1, id, amount }, "sunshine");
    end

    -- 抛出事件
    EventMgr.fire(event.MAKE_SUNSHINE, {["pos"] = pos, })
    return true;
end

-- 获取自动攻击轮次倒计时
function getAttackCountDown()
    local bine = ME.user.bine;
    if not bine or bine:isDead() then
        return nil;
    end

    local round = CombatM.getRound();
    local actionRound = bine.action or 0;

    local cycle = query(bine.classId, "cycle");
    if not cycle or cycle <= 0 then
        return;
    end

    return cycle - (round - actionRound) % cycle;
end

-- 魔藤自动攻击
function attack(para)
    if type(para) == "table" and para.not_move then
        return;
    end

    -- TODO: 随机选择目标攻击
    local bine = ME.user.bine;
    if not bine then
        -- trace("BineM", "没有魔藤对象。");
        return false;
    end

    -- 魔藤已经死亡了
    if bine:isDead() then
        trace("BineM", "魔藤已经死亡了，不能攻击。");
        return false;
    end

    local round = CombatM.getRound();
    local actionRound = bine.action or 0;

    if (actionRound >= round) then
        trace("BineM", "上次行动回合:%d，当前回合:%d", actionRound, round);
        return false;
    end

    local cycle = query(bine.classId, "cycle");
    if type(cycle) ~= "number" or cycle <= 0 then
        trace("BineM", "魔藤 %d 不能攻击。", bine.classId);
        return false;
    end

    if (round - actionRound) % cycle ~= 0 then
        trace("BineM", "当回合不能攻击，round = %d，action = %d", round, actionRound);
        return false;
    end

    -- 如果当前没有花园格子（比如是在各种副本中）
    if getGardenPos() <= 0 then
        trace("BineM", "当前副本没有魔藤。");
        return false;
    end

    bine.action = round;

    -- 玩家死亡了
    if ME.user:isDead() then
        trace("BineM", "玩家死亡了，魔藤不能攻击");
        return false;
    end

    -- 随机选取一个目标
    local grids = {};
    for pos = 1, GRID_SIZE do
        local grid = DungeonM.getGridByPos(pos);
        if grid:isOpened() and grid:isMonster() and not grid.monster:isDead() then
            table.insert(grids, grid);
        end
    end

    if #grids <= 0 then
        bineAttack();
    else
        -- 随机一个
        local rand = DungeonM.getRandSeed("bine_attack") % #grids;
        local grid = grids[rand + 1];

        local pos = grid:getPos();
        if SkillM.canPhysic(bine, grid.monster) then
            -- 如果满足物理攻击条件，先抛出攻击前摇事件
            EventMgr.fire(event.BINE_PRE_ATTACK, { ["pos"] = pos, });
        end

        -- 攻击
        bineAttack(pos);
    end
end

function bineAttack(pos)
    local bine = ME.user.bine;
    if not bine then
        -- trace("BineM", "没有魔藤对象。");
        return false;
    end

    local grid = DungeonM.getGridByPos(pos);
    local round = CombatM.getRound();

    if not pos or pos <= 0 then
        -- 没有目标，增加1点hp、mp
        local hp = bine:getHp() + 1;
        local mp = bine:getMp() + 1;

        hp = math.min(hp, bine:getMaxHp());
        mp = math.min(mp, bine:getMaxMp());

        bine:setHp(hp);
        bine:setMp(mp);

        -- 抛出事件
        EventMgr.fire(event.CURE_BINE, { ["isAuto"] = true, });

        DungeonLogM.addLog(string.format("[BineM]魔藤没有找到攻击目标，当前第%d回合。", round));
        DungeonLogM.addLog(string.format("[BineM]魔藤当前hp为%d，mp为%d。", bine:queryAttrib("hp"), bine:queryAttrib("mp")));
    else
        DungeonLogM.addLog(string.format("[BineM]魔藤攻击目标%d，当前第%d回合。", grid:getPos(), round));

        -- 物理攻击
        if true == SkillM.physic(bine, grid.monster, true) then
            -- 抛出魔藤攻击事件
            EventMgr.fire(event.BINE_ATTACK, { ["pos"] = pos, });
        end
    end
end

-- 获取花园状态
function getGardenState(pos)
    local grid = DungeonM.getGridByPos(pos);

    return grid.garden_state;
end

-- 获取魔藤主动技能
function getInitiativeSkill()
    local bine = ME.user.bine;
    local skills = query(bine.classId, "skills");
    if skills == nil then
        return nil;
    end

    for _, skillId in pairs(skills) do
        if SkillM.query(skillId, "type") == USER_SKILL then
            -- 如果已经学习过，则返回对应等级的技能
            if bine:ownSkill(skillId) then
                local level = bine:getSkillLevel(skillId);
                return SkillM.findSkill(skillId, level);
            end

            -- 未学习过，默认返回初级技能
            return skillId;
        end
    end

    return nil;
end

-- 园丁小屋是否需要保底
function checkGiveBloodyCuscutae()
    -- 正常可获取到的魔藤数据
    if ME.user.bine then
        if ME.user.bine:ownSkill(6001) then
            -- 有该类技能
            return false;
        end
    else
        -- 重启客户端进入时尚未创建魔藤，从玩家身上取
        local info = ME.user.dbase:query("bine");
        if info and info.skills then
            if info.skills.array then
                info.skills = info.skills:toTable();
            end

            local base = SkillM.findBaseSkill(6001);
            for _, id in pairs(info.skills) do
                if SkillM.findBaseSkill(id) == base then
                    -- 有该类技能
                    return false;
                end
            end
        end
    end
    return true;
end

-- 园丁小屋物品对应基础技
function goodBaseSkillInfo()
    return { [204] = 6001, [205] = 6011, [206] = 6021, [207] = 6031 };
end

-- 园丁小屋物品对应最高技
function goodMaxSkillInfo()
    return { [204] = 6005, [205] = 6015, [206] = 6025, [207] = 6035 };
end

-- 魔藤某物品对应技能是否满级
function checkSkillLevelMax(goodId)
    local maxSkill  = goodMaxSkillInfo()[goodId];

    -- 正常可获取到的魔藤数据
    if ME.user.bine then
        local skills = ME.user.bine:getSkills() or {};
        if table.indexOf(skills, maxSkill) ~= -1 then
           -- 满级
           return true;
        end
    else
        -- 重启客户端进入时尚未魔藤，从玩家身上取
        local info = ME.user.dbase:query("bine");
        if info and info.skills then
            if info.skills.array then
                info.skills = info.skills:toTable();
            end

            for _, id in pairs(info.skills) do
                if table.indexOf(info.skills, maxSkill) ~= -1 then
                    -- 满级
                    return true;
                end
            end
        end
    end

    return false;
end

-- 同步下数据到dbase下
function syncBineData()
    local bine = ME.user.bine;
    if bine then
        ME.user.dbase:set("bine", bine:getSaveData());
        return;
    end
end
